require 'rsense/infer'

module RSense
  class SuggestResult
    attr_reader :candidates, :prefix

    def initialize(candidates, prefix)
      @candidates = candidates
      @prefix = prefix
    end
  end

  class CodeAssist < Inferrer
    SuggestMethodName = '__suggest__'

    def initialize
      super
      @candidates = Set.new
      @colon2 = false
      add_call_handler(method(:on_suggest))
    end

    def suggest(name, source, point)
      @candidates.clear

      # fix source to correct and prepare to
      # collect completions.
      # ex) a.    => a.__suggest__
      #     a.fo  => a.__suggest__ (filter by `fo' later)
      prefix = ''
      first1 = source.rindex('.', point)
      first2 = source.rindex('::', point)
      if first1 and (first2.nil? or first1 >= first2)
        @colon2 = false
        prefix = source[first1+1..point-1]
        source[first1+1..point-1] = SuggestMethodName
        clear
        infer(source)
      elsif first2 and (first1.nil? or first2 > first1)
        @colon2 = true
        prefix = source[first2+2..point-1]
        source[first2..point-1] = '.' + SuggestMethodName
        clear
        infer(source)
      end

      return SuggestResult.new(@candidates.to_a, prefix)
    end

    def on_suggest(receiver, selector)
      if selector.to_s == SuggestMethodName
        @candidates += @colon2 ? receiver.meta.constants.keys : receiver.methods
      end
    end
  end
end

